//
//  TYSearchController.m
//  TYUIKit
//
//  Created by TuyaInc on 2019/1/23.
//

#import "TYSearchController.h"

#import "TYUIKit.h"
#import "Masonry.h"

#if __has_include(<TYNavigationController/UIViewController+TYNavigation.h>)
#import <TYNavigationController/UIViewController+TYNavigation.h>
#elif __has_include("UIViewController+TYNavigation.h")
#import "UIViewController+TYNavigation.h"
#endif

#import "TYSearchBarContainer.h"
#import "TYSearchReadyDefaultViewController.h"
#import "TYSearchControllerAppearance.h"
#import "TYSearchTableCustomProtocol.h"

#import "TYIQKeyboardManagerDisableProtocol.h"
//#import "TYTheme.h"
#define TY_BarAppearance [TYSearchControllerAppearance appearance].searchBarAppearance

#define TY_SearchBarDefaultHeight (TY_IsIOS(11.0) ? 56 : 44)
#define TY_SearchBarFieldDefaultTopInset (10)

@interface TYSearchController () <UITableViewDataSource>

@property (nonatomic, strong) NSObject<TYSearchTableCustomProtocol> *tableFrom;    /**< tableView可以由外部传入 */
@property (nonatomic, strong) UITableView *tableView;
@property (nonatomic, strong) TYSearchBar *searchBar;

@property (nonatomic) TYSearchControllerStatus searchStatus;

// searchBarf放在searchBarHeader上，searchBarHeader放在tableView的header
@property (nonatomic, strong) TYSearchBarContainer *searchBarContainer;
// 用来填充searchBar顶部与屏幕顶部的间隙
@property (nonatomic, strong) UIView *statusBarFillView;

@property (nonatomic) CGPoint lastCotentOffset;
@property (nonatomic) NSInteger dragDirection;    // -1: 向下，contentOffset减小  0: 静止  1: 向上

@property (nonatomic) CGFloat keyboardInset;    // 用来记录因键盘出现而做出的inset

@end

@implementation TYSearchController

+ (void)load {
    Class<TYIQKeyboardManagerDisableProtocol> cls = NSClassFromString(kIQKeyboardManagerClassName);
    if (cls && [cls respondsToSelector:@selector(sharedManager)]) {
        id<TYIQKeyboardManagerDisableProtocol> target = [cls sharedManager];
        if ([target respondsToSelector:@selector(disabledDistanceHandlingClasses)]) {
            [target.disabledDistanceHandlingClasses addObject:self];
        }
        if ([target respondsToSelector:@selector(disabledTouchResignedClasses)]) {
            [target.disabledTouchResignedClasses addObject:self];
        }
    }
}

- (instancetype)init {
    if (self = [super init]) {
        self.searchReadyController = [TYSearchReadyDefaultViewController new];
        _tableStyle = UITableViewStylePlain;
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.edgesForExtendedLayout = UIRectEdgeNone;
    self.automaticallyAdjustsScrollViewInsets = NO;
    self.definesPresentationContext = YES;
//    self.view.backgroundColor = [TYTheme theme].app_bg_color;
    
    
    [self _setupNavi];
    [self _setupSearch];
    [self _setupTable];
    
    _searchStatus = TYSearchControllerStatus_Normal;
    
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(searchControllerKeyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(searchControllerKeyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(searchControllerKeyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(searchControllerKeyboardDidHide:) name:UIKeyboardDidHideNotification object:nil];
    [_tableView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
   
    self.searchStatus = _searchBar.isFirstResponder ? (_searchBar.text.length > 0 ? TYSearchControllerStatus_Result : TYSearchControllerStatus_Ready) : TYSearchControllerStatus_Normal;
}

- (void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    
// 在激活状态侧滑返回有点问题，如果使用了TYNavi则没问题
#if !__has_include(<TYNavigationController/UIViewController+TYNavigation.h>) && !__has_include("UIViewController+TYNavigation.h")
    [self searchBarCancelButtonClicked:self.searchBar];
#endif
}

- (void)dealloc {
    [_tableView removeObserver:self forKeyPath:@"contentOffset"];
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

- (void)_setupNavi {
    
#if __has_include(<TYNavigationController/UIViewController+TYNavigation.h>) || __has_include("UIViewController+TYNavigation.h")
    self.ty_topBarSeparatorAlpha = 0;
#endif
}

- (BOOL)ty_enableTYNaviRender {
    return YES;
}

- (void)_setupSearch {
    _searchBar = [[TYSearchBar alloc] init];
    [_searchBar sizeToFit];
    _searchBar.delegate = self;
#if __has_include(<TYNavigationController/TYNavigationPresentProtocol.h>) || __has_include("TYNavigationPresentProtocol.h")
    _searchBar.backgroundColor = [TYTheme theme].status_bg_color;
    self.ty_topBarBlurAlpha = 0;
#else
    _searchBar.backgroundColor = TY_BarAppearance.backgroundColor;
#endif
    
    _searchBar.accessibilityIdentifier = [TYSearchControllerAppearance appearance].searchBarAppearance.searchAccessibilityIdentifier;
    
    [_searchBar addGestureRecognizer:[[UIPanGestureRecognizer alloc] init]];
    
    _searchBar.ty_textFieldInsets = TY_BarAppearance.searchFieldInsets;
    _searchBar.ty_cancelButtonInsets = TY_BarAppearance.cancelButtonInsets;
    
    _searchBar.tintColor = TY_BarAppearance.tintColor;
    _searchBar.placeholder = TY_BarAppearance.placeholder;
    _searchBar.ty_separatorColor = TY_BarAppearance.separatorColor;
    _searchBar.translucent = TY_BarAppearance.translucent;
    
    _searchBar.ty_textField.layer.cornerRadius = TY_BarAppearance.searchFieldCorner;
    _searchBar.ty_textField.font = TY_BarAppearance.searchTextFont;
    _searchBar.ty_textField.textColor = TY_BarAppearance.searchTextColor;
    _searchBar.ty_textField.backgroundColor = TY_BarAppearance.searchFieldBackgroundColor;
    
    [_searchBar setSearchTextPositionAdjustment:TY_BarAppearance.searchTextOffset];
}

- (void)_setupTable {
    if ([TYSearchControllerAppearance appearance].searchTableClass &&
        !_disableApperanceTableClass) {
        _tableFrom = [[TYSearchControllerAppearance appearance].searchTableClass new];
        _tableFrom.searchController = self;
        _tableView = [_tableFrom tableViewWithFrame:CGRectZero style:_tableStyle];
    } else {
        _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:_tableStyle];
    }
    
    _tableView.backgroundColor = [TYSearchControllerAppearance appearance].searchTableBackgroundColor ? : [UIColor whiteColor];
    
    if ([self respondsToSelector:@selector(searchControllerTableViewInitial)]) {
        [self searchControllerTableViewInitial];
    }
    if (UIEdgeInsetsEqualToEdgeInsets(UIEdgeInsetsZero, _tableView.contentInset)) {
        _tableView.contentInset = UIEdgeInsetsMake(0, 0, TY_ScreenSafeBottom(), 0);
    }
    if (@available(iOS 11.0, *)) {
        _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
    }
    if (!_tableView.delegate) {
        _tableView.delegate = self;
    }
    if (!_tableView.dataSource) {
        _tableView.dataSource = self;
    }
    
    if (_tableView.superview != self.view) {
        [self.view addSubview:_tableView];
    }
    [_tableView mas_remakeConstraints:^(MASConstraintMaker *make) {
        make.left.bottom.right.mas_equalTo(self.view);
        make.top.mas_equalTo(self.view.mas_top).offset(0);
    }];
    
    _searchBarContainer = [[TYSearchBarContainer alloc] initWithSearchBar:_searchBar];
    _tableView.tableHeaderView = _searchBarContainer;
    _searchBarContainer.ty_height = _searchBar.ty_height - [TYSearchControllerAppearance appearance].searchBarBoundsInsets.top - [TYSearchControllerAppearance appearance].searchBarBoundsInsets.bottom;
    _searchBar.ty_bottom = _searchBarContainer.ty_height + [TYSearchControllerAppearance appearance].searchBarBoundsInsets.bottom;
    _statusBarFillView = [UIView new];
    _statusBarFillView.backgroundColor = _searchBar.backgroundColor;
    [self.view insertSubview:_statusBarFillView atIndex:0];
    
    [_statusBarFillView mas_makeConstraints:^(MASConstraintMaker *make) {
        make.top.left.right.mas_equalTo(self.view);
        make.bottom.mas_equalTo(self.tableView.mas_top);
    }];
}

- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
    CGPoint contentOffset = scrollView.contentOffset;
    if (!decelerate && ![_searchBar isFirstResponder] && contentOffset.y < _tableView.tableHeaderView.ty_height) {
        CGFloat threshold = _tableView.tableHeaderView.ty_height / 3.0 * (_dragDirection < 0 ? 2 : 1);
        [self.tableView setContentOffset:CGPointMake(0, contentOffset.y > threshold ? _tableView.tableHeaderView.ty_height : 0) animated:YES];
    }
    _dragDirection = 0;
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if (object == _tableView && [keyPath isEqualToString:@"contentOffset"]) {
        CGPoint contentOffset = _tableView.contentOffset;
        if (_tableView.isDragging) {
            if (contentOffset.y < _lastCotentOffset.y) {
                _dragDirection = -1;
            } else if (contentOffset.y > _lastCotentOffset.y) {
                _dragDirection = 1;
            }
        }
        _lastCotentOffset = contentOffset;
        
        if (_searchBar.superview == _searchBarContainer) {
            CGFloat offset = _searchStatus == TYSearchControllerStatus_Normal && contentOffset.y >= 0 ? 0 : contentOffset.y;
            _searchBar.ty_bottom = _searchBarContainer.ty_height + offset + [TYSearchControllerAppearance appearance].searchBarBoundsInsets.bottom;
        }
        
#if __has_include(<TYNavigationController/TYNavigationPresentProtocol.h>) || __has_include("TYNavigationPresentProtocol.h")
        CGRect searchBarFrame = [self.navigationController.view convertRect:self.searchBar.frame fromView:self.searchBar.superview];
        CGRect naviFrame = self.navigationController.navigationBar.frame;
        // iOS11.0以下，会提前回调kvo，此时tableView的frame有问题，导致searchBarFrame错误
        BOOL showNaviSeparator = naviFrame.origin.y + naviFrame.size.height >= searchBarFrame.origin.y + searchBarFrame.size.height && self.tableView.frame.origin.x >= 0 && self.tableView.frame.origin.y >= 0;
        if (self.ty_naviPresentSeparatorAlpha != showNaviSeparator ? 1 : 0) {
            self.ty_topBarSeparatorAlpha = showNaviSeparator ? 1 : 0;
        }
#endif
    }
}

#pragma mark - <UITableViewDataSource>
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 0;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return 0;
}

#pragma mark - <TYSearchBarDelegate>
- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar {
    [self _searchInputBegin];
    return YES;
}

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar {
    [self _searchInputEnd];
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
    TYSearchControllerStatus lastStatus = self.searchStatus;
    self.searchStatus = _searchBar.text.length > 0 ? TYSearchControllerStatus_Result : TYSearchControllerStatus_Ready;
    
    if (self.searchStatus == TYSearchControllerStatus_Ready) {
        [self _setupReadyVC];
        if ([self.searchReadyController respondsToSelector:@selector(viewControllerWillAppearWithAnimation:)]) {
            [self.searchReadyController viewControllerWillAppearWithAnimation:NO];
        }
        if ([self.searchReadyController respondsToSelector:@selector(viewControllerDidAppear)]) {
            [self.searchReadyController viewControllerDidAppear];
        }
    } else if (lastStatus == TYSearchControllerStatus_Ready) {
        if ([self.searchReadyController respondsToSelector:@selector(viewControllerWillDisappearWithAnimation:)]) {
            [self.searchReadyController viewControllerWillDisappearWithAnimation:NO];
        }
//        [self.searchReadyController.view removeFromSuperview];
//        [self.searchReadyController removeFromParentViewController];
        if ([self.searchReadyController respondsToSelector:@selector(viewControllerDidDisappear)]) {
            [self.searchReadyController viewControllerDidDisappear];
        }
    }
    
    if (!self.searchResultController && self.searchBar.text.length == 0) {
        [self.tableView setContentOffset:CGPointZero animated:NO];
    }
    
    if (_tableFrom && [_tableFrom respondsToSelector:@selector(searchController:textDidChange:)]) {
        [_tableFrom searchController:self textDidChange:searchText];
    } else if (!self.searchResultController
                   && (self.searchStatus == TYSearchControllerStatus_Result || lastStatus == TYSearchControllerStatus_Result)) {
        [self.tableView reloadData];
    }
}

- (void)ty_searchBarCancelButtonInitial {
    _searchBar.ty_cancelButton.titleLabel.font = TY_BarAppearance.cancelButtonFont;
    [_searchBar.ty_cancelButton setTitleColor:TY_BarAppearance.cancelButtonNormalColor forState:UIControlStateNormal];
    [_searchBar.ty_cancelButton setTitleColor:TY_BarAppearance.cancelButtonHighlightColor forState:UIControlStateHighlighted];
    [_searchBar.ty_cancelButton setTitleColor:TY_BarAppearance.cancelButtonDisableColor forState:UIControlStateDisabled];

    _searchBar.ty_cancelButton.accessibilityIdentifier = [TYSearchControllerAppearance appearance].searchBarAppearance.cancelAccessibilityIdentifier;
    
    if ([self respondsToSelector:@selector(searchControllerRightButtonInitial)]) {
        [self searchControllerRightButtonInitial];
    }
}

#pragma mark - <TYViewControllerNaviCallback>
- (BOOL)ty_naviPopGestureShouldBegin {
    return self.searchStatus == TYSearchControllerStatus_Normal;
}

#pragma mark - Override
- (void)setTy_topBarBackgroundColor:(UIColor *)ty_topBarBackgroundColor {
#if __has_include(<TYNavigationController/UIViewController+TYNavigation.h>) || __has_include("UIViewController+TYNavigation.h")
    if ([super respondsToSelector:@selector(setTy_topBarBackgroundColor:)]) {
        [super setTy_topBarBackgroundColor:ty_topBarBackgroundColor];
    }
    _searchBar.backgroundColor = self.ty_topBarBackgroundColor;
    _statusBarFillView.backgroundColor = _searchBar.backgroundColor;
#endif
}

#pragma mark - Notification
- (void)searchControllerKeyboardWillShow:(NSNotification *)notif {}
- (void)searchControllerKeyboardDidHide:(NSNotification *)notif {}

- (void)searchControllerKeyboardDidShow:(NSNotification *)notif {
    CGRect endFrame = [[notif.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];
    UIEdgeInsets inset = self.tableView.contentInset;
    inset.bottom -= _keyboardInset; // didShow可能会多次回调，需要去掉上次的，避免重复计算
    _keyboardInset = MAX(0, TY_ScreenHeight() - endFrame.origin.y);
    inset.bottom = inset.bottom + _keyboardInset;
    self.tableView.contentInset = inset;
}

- (void)searchControllerKeyboardWillHide:(NSNotification *)notif {
    UIEdgeInsets inset = self.tableView.contentInset;
    inset.bottom = inset.bottom - _keyboardInset;
    self.tableView.contentInset = inset;
    _keyboardInset = 0;
}

#pragma mark - Accessor
- (void)setSearchReadyController:(__kindof UIViewController<TYSearchReadyControllerProtocol> *)searchReadyController {
    if (_searchReadyController != searchReadyController) {
        if ([_searchReadyController respondsToSelector:@selector(setSearchController:)]) {
            _searchReadyController.searchController = nil;
        }
        
        _searchReadyController = searchReadyController;
        
        if ([_searchReadyController respondsToSelector:@selector(setSearchController:)]) {
            _searchReadyController.searchController = self;
        }
    }
}

- (void)setSearchStatus:(TYSearchControllerStatus)status {
    if (_searchStatus != status) {
        _searchStatus = status;
        if (_tableFrom && [_tableFrom respondsToSelector:@selector(searchControllerStatusDidChanged:)]) {
            [_tableFrom searchControllerStatusDidChanged:self];
        } else if ([self respondsToSelector:@selector(searchControllerStatusDidChanged)]) {
            [self searchControllerStatusDidChanged];
        }
    }
}

#pragma mark - Callback
- (void)searchControllerStatusDidChanged {}

- (void)searchControllerRightButtonInitial {
}

#pragma mark - Private
- (void)_searchInputBegin {
    [self.navigationController setNavigationBarHidden:YES animated:YES];
    [self.searchBar setShowsCancelButton:YES animated:YES];
    CGFloat offset = 0;
    if (TY_IsNotchScreen()) {
        offset = TY_ScreenSafeTop();
    } else if ([[UIApplication sharedApplication] isStatusBarHidden]) {
        offset = 0;
    } else {
        // 在默认的情况下，searchBar的上下间距都是10
        offset = 20 - (TY_SearchBarFieldDefaultTopInset + TY_BarAppearance.searchFieldInsets.top - [TYSearchControllerAppearance appearance].searchBarBoundsInsets.top);
    }
    [_tableView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.view.mas_top).offset(offset);
    }];
    
    [UIView animateWithDuration:UINavigationControllerHideShowBarDuration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.view layoutIfNeeded];
        if (self.searchBar.text.length == 0) {
            [self _setupReadyVC];
            
            if ([self.searchReadyController respondsToSelector:@selector(viewControllerWillAppearWithAnimation:)]) {
                [self.searchReadyController viewControllerWillAppearWithAnimation:YES];
            }
        }
    } completion:^(BOOL finished) {
        self.searchStatus = self.searchBar.text.length > 0 ? TYSearchControllerStatus_Result : TYSearchControllerStatus_Ready;
        
        CGRect targetFrame = [self.view convertRect:self.searchBar.frame fromView:self.searchBar.superview];
        [self.view addSubview:self.searchBar];
        self.searchBar.frame = targetFrame;
        
        if (self.searchBar.text.length == 0 && [self.searchReadyController respondsToSelector:@selector(viewControllerDidAppear)]) {
            [self.searchReadyController viewControllerDidAppear];
        }
    }];
}

- (void)_searchInputEnd {
    [self.view endEditing:YES];
    _searchBar.text = nil;
    
    TYSearchControllerStatus lastStatus = self.searchStatus;
    self.searchStatus = TYSearchControllerStatus_Normal;
    
    [self.tableView setContentOffset:CGPointZero animated:NO];
    if (!_searchResultController) {
        // 重置table数据到normal状态
        [self.tableView reloadData];
    }
    
    [_searchBar setShowsCancelButton:NO animated:YES];
    [self.navigationController setNavigationBarHidden:NO animated:YES];
    [_tableView mas_updateConstraints:^(MASConstraintMaker *make) {
        make.top.mas_equalTo(self.view).offset(0);
    }];
    
    [UIView animateWithDuration:UINavigationControllerHideShowBarDuration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        [self.view layoutIfNeeded];
        if (lastStatus == TYSearchControllerStatus_Ready && [self.searchReadyController respondsToSelector:@selector(viewControllerWillDisappearWithAnimation:)]) {
            [self.searchReadyController viewControllerWillDisappearWithAnimation:YES];
        }
        self.searchBar.ty_bottom = self.searchBarContainer.ty_height;
    } completion:^(BOOL finished) {

        [self.searchBarContainer addSubview:self.searchBar];
        CGFloat offset = self.searchStatus == TYSearchControllerStatus_Normal && self.tableView.contentOffset.y >= 0 ? 0 : self.tableView.contentOffset.y;
        self.searchBar.ty_bottom = self.searchBarContainer.ty_height + offset;
        
//            [self.searchReadyController.view removeFromSuperview];
//            [self.searchReadyController removeFromParentViewController];
        if (lastStatus == TYSearchControllerStatus_Ready && [self.searchReadyController respondsToSelector:@selector(viewControllerDidDisappear)]) {
            [self.searchReadyController viewControllerDidDisappear];
        }
    }];
}

- (void)_setupReadyVC {
    if (_searchReadyController.view.superview != self.view) {
        [self.view addSubview:_searchReadyController.view];
        [_searchReadyController.view mas_makeConstraints:^(MASConstraintMaker *make) {
            make.top.mas_equalTo(self.searchBar.mas_bottom);
            make.left.right.bottom.mas_equalTo(self.view);
        }];
        [self addChildViewController:_searchReadyController];
    }
}

- (void)_setupResultVC {
    
}

#pragma mark - Rotation
- (BOOL)shouldAutorotate {
    return YES;
}

- (UIInterfaceOrientationMask)supportedInterfaceOrientations {
    return UIInterfaceOrientationMaskPortrait;
}

#pragma mark - present style
- (UIModalPresentationStyle)modalPresentationStyle {
    return UIModalPresentationFullScreen;
}
    
@end
